package com.dxx.cloud.admin.utils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.dxx.cloud.admin.constant.CommonConst;
import com.dxx.cloud.admin.module.entity.BaseEntity;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author duh
 * @create 2019/12/27 14:11
 **/
@Slf4j
public class EntityUtils {

    public static final String SERIAL_VERSION_UID_KEY = "serialVersionUID";
    /***
     * 添加单个实体
     */
    public static <T extends BaseEntity> Long addEntity(BaseMapper<T> mapper, Class<T> clazz, Object request) {
        T entity = BeanUtils.instantiateClass(clazz);
        BeanUtils.copyProperties(request, entity);
        entity.setIsDeleted(CommonConst.EntityStatus.NOT_DELETED);
        if (null == entity.getCreated()) {
            entity.setCreated(new Date());
        }
        mapper.insert(entity);
        return entity.getId();
    }

    /***
     * 更新单个实体
     */
    public static <T extends BaseEntity> Long updateEntityById(BaseMapper<T> mapper, Serializable id, Object request) {
        T entity = mapper.selectById(String.valueOf(id));
        boolean ret = false;
        if (null != entity) {
            BeanUtils.copyProperties(request, entity);
            entity.setUpdated(new Date());
            ret = SqlHelper.retBool(mapper.updateById(entity));
        }
        return ret ? entity.getId() : 0;
    }

    public static <T extends BaseEntity> Long updateEntityByIdWithoutUpdated(BaseMapper<T> mapper, Serializable id, Object request) {
        T entity = mapper.selectById(String.valueOf(id));
        boolean ret = false;
        if (null != entity) {
            BeanUtils.copyProperties(request, entity);
            ret = SqlHelper.retBool(mapper.updateById(entity));
        }
        return ret ? entity.getId() : 0;
    }

    /**
     * 查询单个实体
     */
    public static <T extends BaseEntity> T selectEntity(BaseMapper<T> mapper, Class<T> clazz, Object request)  {
        QueryWrapper<T> queryWrapper = buildQueryWrapper(clazz, request);
        if(null == queryWrapper) {
            return null;
        }
        return mapper.selectOne(queryWrapper, false);
    }

    public static <T extends BaseEntity> T selectInvalidEntity(BaseMapper<T> mapper, Class<T> clazz, Object request)  {
        T entity = BeanUtils.instantiateClass(clazz);
        BeanUtils.copyProperties(request, entity);
        entity.setIsDeleted(CommonConst.EntityStatus.DELETED);
        return selectEntity(mapper, clazz, entity);
    }

    /***
     * 逻辑删除单个实体
     */
    public static <T extends BaseEntity> Boolean deleteEntityById(BaseMapper<T> mapper, Serializable id, String updater) {
        return SqlHelper.retBool(mapper.update(new LambdaUpdateWrapper<T>().set(BaseEntity::getIsDeleted, CommonConst.EntityStatus.DELETED)
                .set(StringUtils.hasText(updater), BaseEntity::getUpdater, updater)
                .eq(BaseEntity::getId, id)));
    }


    /**
     * 获取entity列表
     *
     * @param clazz
     * @return
     * @throws Exception
     */
    public static <T extends BaseEntity> List<T> getEntityList(BaseMapper<T> mapper, Class<T> clazz, Object request)  {
        final QueryWrapper<T> queryWrapper = buildQueryWrapper(clazz, request);
        if (queryWrapper == null) {
            return List.of();
        }
        return mapper.selectList(queryWrapper);
    }

    private static <T extends BaseEntity>  QueryWrapper<T> buildQueryWrapper(Class<T> clazz, Object request)  {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        boolean hasValue = false;
        T entity = BeanUtils.instantiateClass(clazz);
        BeanUtils.copyProperties(request, entity);
        for (Field declaredField : clazz.getDeclaredFields()) {
            if(SERIAL_VERSION_UID_KEY.equals(declaredField.getName())) {
                continue;
            }
            declaredField.setAccessible(true);
            Object val = null;
            try {
                val = declaredField.get(entity);
                if (null == val) {
                    Field declaredField1 = request.getClass().getDeclaredField(declaredField.getName());
                    declaredField1.setAccessible(true);
                    if(declaredField1.get(request) != null) {
                        val = declaredField1.get(request);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            if (null != val) {
                queryWrapper.eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(declaredField.getName()), val);
                hasValue = true;
            }
        }
        if (!hasValue) {
            return null;
        }
        return queryWrapper;
    }

    /**
     * 根据单属性获取entity列表
     *
     * @param clazz
     * @return
     * @throws Exception
     */
    public static <T> List<T> getEntityListBySinglePro(BaseMapper<T> mapper, Class<T> clazz, String name, String value)  {
        final long count = Arrays.stream(clazz.getDeclaredFields()).map(Field::getName).filter(name::equals).count();
        if(count > 0 && StringUtils.hasText(value)) {
            return mapper.selectList(new QueryWrapper<T>().eq(name, value));
        }
        return null;
    }

    /***
     * 返回list
     */
    public static <T extends BaseEntity, R> List<R> responseList(BaseMapper<T> mapper, Class<T> entityClazz, Class<R> responseClazz, Object request)  {
        List<T> entitys = getEntityList(mapper, entityClazz, request);
        List<R> responses = new ArrayList<>();
        if (null != responseClazz && null != entitys && !entitys.isEmpty()) {
            for (T entity : entitys) {
                responses.add(entity2Response(responseClazz, entity));
            }
        }
        return responses;
    }

    /**
     * entity转response
     *
     * @param responseClazz
     * @param entity
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> R entity2Response(Class<R> responseClazz, T entity) {
        R response = null;
        if (null != entity) {
            response = BeanUtils.instantiateClass(responseClazz);
            BeanUtils.copyProperties(entity, response);
        }
        return response;
    }

    public static <T, R> List<R> entityList2ResponseList(Class<R> responseClazz, List<T> entityList) {
        if(!CollectionUtils.isEmpty(entityList)) {
            return entityList.stream().map(entity -> entity2Response(responseClazz, entity)).collect(Collectors.toList());
        }
        return List.of();
    }

    public static <T, R> Page<R> page2PageResponse(Class<R> responseClazz, Page<T> page) {
        Page<R> pageResponse = null;
        if(null != page) {
            pageResponse = new Page<>();
            BeanUtils.copyProperties(page, pageResponse);
            if (CollectionUtils.isEmpty(page.getRecords())) {
                pageResponse.setRecords(entityList2ResponseList(responseClazz, page.getRecords()));
            }
        }
        return pageResponse;
    }

    /**
     * 查询分页列表
     *
     * @param mapper
     * @param entityClazz
     * @param request
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T extends BaseEntity> TableDataInfo<T> pageInfoModel(BaseMapper<T> mapper, Class<T> entityClazz, PageQuery request) {
        final QueryWrapper<T> tQueryWrapper = buildQueryWrapper(entityClazz, request);
        if(null == tQueryWrapper) {
            return TableDataInfo.build();
        }
        tQueryWrapper.orderByDesc(List.of("id","updated"));
        final Page<T> page = mapper.selectPage(new Page<>(request.getPageNum(), request.getPageSize()), buildQueryWrapper(entityClazz, request));
        return TableDataInfo.build(page);
    }

    public static R buildResponseModelByInteger(Long result) {
        if (null == result || result <= 0) {
            return R.fail();
        } else {
            return R.ok(result);
        }
    }


    public static void setCreator(Object entity,String operator) {
        if (StringUtils.hasText(operator)) {
            try {
                Method setCreator = entity.getClass().getMethod("setCreator", String.class);
                setCreator.invoke(entity, operator);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    public static void setUpdater(Object entity,String operator) {
        if (StringUtils.hasText(operator)) {
            try {
                Method setCreator = entity.getClass().getMethod("setUpdater", String.class);
                setCreator.invoke(entity, operator);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
